/* Vecmath.

   Copyright (C) 2001, 2002, 2003 Stefan Maierhofer.

   Written by Stefan Maierhofer <sm@cg.tuwien.ac.at>

   This file is part of Vecmath.

   Vecmath is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   Vecmath is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   aint with Vecmath; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */

using System;
using NUnit.Framework;

namespace Vecmath
{

    /// <summary>
    /// Vec2I.
    /// </summary>
    public struct Vec2I
    {
        public static Vec2I Identity = new Vec2I(0);
        public static Vec2I UnitX = new Vec2I(1,0);
        public static Vec2I UnitY = new Vec2I(0,1);

        public Vec2I(int xy)
        {
            _x = new int[2];
            _x[0] = xy; _x[1] = xy;
        }

        public Vec2I(int x, int y)
        {
            _x = new int[2];
            _x[0] = x; _x[1] = y;
        }

        public Vec2I(ref int [] x)
        {
            _x = new int[2];
            _x[0] = x[0]; _x[1] = x[1];
        }

        public int this [int index]
        {
            get { return _x[index]; }
            set { _x[index] = value; }
        }

        public int x
        {
            get { return _x[0]; }
            set { _x[0] = value; }
        }

        public int y
        {
            get { return _x[1]; }
            set { _x[1] = value; }
        }

        public static explicit operator Vec2I(Vec2F v)
        {
            return new Vec2I((int)v.x, (int)v.y);
        }

        public static explicit operator Vec2I(Vec2D v)
        {
            return new Vec2I((int)v.x, (int)v.y);
        }

        public static Vec2I operator+(Vec2I v, int f)
        {
            return new Vec2I(v[0] + f, v[1] + f);
        }

        public static Vec2I operator+(Vec2I v, Vec2I w)
        {
            return new Vec2I(v[0] + w[0], v[1] + w[1]);
        }

        public static Vec2I operator-(Vec2I v, int f)
        {
            return new Vec2I(v[0] - f, v[1] - f);
        }

        public static Vec2I operator-(Vec2I v, Vec2I w)
        {
            return new Vec2I(v[0] - w[0], v[1] - w[1]);
        }

        public static Vec2I operator-(Vec2I v)
        {
            return new Vec2I(-v[0], -v[1]);
        }

        public static Vec2I operator*(Vec2I v, int f)
        {
            return new Vec2I(v[0] * f, v[1] * f);
        }

        public static Vec2I operator*(Vec2I v, Vec2I w)
        {
            return new Vec2I(v[0] * w[0], v[1] * w[1]);
        }

        public static Vec2I operator/(Vec2I v, int f)
        {
            return new Vec2I(v[0] / f, v[1] / f);
        }

        public static Vec2I operator%(Vec2I v, int f)
        {
            return new Vec2I(v[0] % f, v[1] % f);
        }

        public static int Dot(Vec2I u, Vec2I v)
        {
            return u[0] * v[0] + u[1] * v[1];
        }

        public double SquaredLength
        {
            get { return _x[0] * _x[0] + _x[1] * _x[1]; }
        }

        public double Length
        {
            get { return Math.Sqrt(SquaredLength); }
        }

        public int MinDim
        {
            get
            {
                return (_x[0] < _x[1]) ? 0 : 1;
            }
        }

        public int MaxDim
        {
            get
            {
                return (_x[0] > _x[1]) ? 0 : 1;
            }
        }

        public int Minimum
        {
            get
            {
                return (_x[0] < _x[1]) ? _x[0] : _x[1];
            }
        }

        public int Maximum
        {
            get
            {
                return (_x[0] > _x[1]) ? _x[0] : _x[1];
            }
        }

        public static bool operator<(Vec2I a, Vec2I b)
        {
            return (
                a._x[0] < b._x[0] &&
                a._x[1] < b._x[1]
                );
        }

        public static bool operator<=(Vec2I a, Vec2I b)
        {
            return (
                a._x[0] <= b._x[0] &&
                a._x[1] <= b._x[1]
                );
        }

        public static bool operator==(Vec2I a, Vec2I b)
        {
            return (
                a._x[0] == b._x[0] &&
                a._x[1] == b._x[1]
                );
        }

        public static bool operator!=(Vec2I a, Vec2I b)
        {
            return (
                a._x[0] != b._x[0] ||
                a._x[1] != b._x[1]
                );
        }

        public static bool operator>=(Vec2I a, Vec2I b)
        {
            return (
                a._x[0] >= b._x[0] &&
                a._x[1] >= b._x[1]
                );
        }

        public static bool operator>(Vec2I a, Vec2I b)
        {
            return (
                a._x[0] > b._x[0] &&
                a._x[1] > b._x[1]
                );
        }

        public static Vec2I Min(Vec2I a, Vec2I b)
        {
            return new Vec2I(
                Math.Min(a._x[0], b._x[0]),
                Math.Min(a._x[1], b._x[1])
                );
        }

        public static Vec2I Max(Vec2I a, Vec2I b)
        {
            return new Vec2I(
                Math.Max(a._x[0], b._x[0]),
                Math.Max(a._x[1], b._x[1])
                );
        }

        internal int [] _x;

        public override bool Equals(object obj)
        {
            Vec2I x = (Vec2I)obj;
            return (
                _x[0] == x._x[0] &&
                _x[1] == x._x[1]
                );
        }

        public override int GetHashCode()
        {
            return base.GetHashCode ();
        }

        public override string ToString()
        {
            return "Vec2I(" + _x[0] + ", " + _x[1] + ")";
        }

        static Vec2I()
        {
            System.Threading.Thread.CurrentThread.CurrentCulture =
                System.Globalization.CultureInfo.InvariantCulture;
        }
    }
    

    [TestFixture]
    public class Vec2ITest
    {
        [Test]
        public void Initialization()
        {
            Vec2I v;

            v = Vec2I.Identity;
            Assert.IsTrue(
                v._x[0] == 0 && v._x[1] == 0
                );

            v = Vec2I.UnitX;
            Assert.IsTrue(
                v._x[0] == 1 && v._x[1] == 0
                );

            v = Vec2I.UnitY;
            Assert.IsTrue(
                v._x[0] == 0 && v._x[1] == 1
                );

            v = new Vec2I(3);
            Assert.IsTrue(
                v._x[0] == 3 && v._x[1] == 3
                );
            
            v = new Vec2I(1, 2);
            Assert.IsTrue(
                v._x[0] == 1 && v._x[1] == 2
                );

            int [] fa = { 1, 2 };
            v = new Vec2I(ref fa);
            Assert.IsTrue(
                v._x[0] == 1 && v._x[1] == 2
                );
        }

        [Test]
        public void Accessors()
        {
            Vec2I v = new Vec2I(1, 2);
            Assert.IsTrue(
                v._x[0] == v[0] && v._x[1] == v[1]
                );
            Assert.IsTrue(
                v._x[0] == v.x && v._x[1] == v.y
                );
        }

        [Test]
        public void ScalarOperators()
        {
            Vec2I v = new Vec2I(1, 2);

            v += 1;
            Assert.IsTrue(v == new Vec2I(2, 3));

            v -= 1;
            Assert.IsTrue(v == new Vec2I(1, 2));
            
            v *= 2;
            Assert.IsTrue(v == new Vec2I(2, 4));

            v /= 2;
            Assert.IsTrue(v == new Vec2I(1, 2));
        }

        [Test]
        public void VecOperators()
        {
            Vec2I v;

            v = new Vec2I(1,2) + new Vec2I(3,2);
            Assert.IsTrue(v == new Vec2I(4, 4));

            v = new Vec2I(1,2) - new Vec2I(3,2);
            Assert.IsTrue(v == new Vec2I(-2, 0));
        }

        [Test]
        public void Length()
        {
            Vec2I v = new Vec2I(11, 17);
            Assert.IsTrue(v.Length * v.Length == v.SquaredLength);
        }

        [Test]
        public void RelationalOperators()
        {
            Assert.IsTrue(new Vec2I(2,3) < new Vec2I(3,10));
            Assert.IsTrue(new Vec2I(2,3) <= new Vec2I(3,10));
            Assert.IsTrue(new Vec2I(2,3) != new Vec2I(3,10));
            Assert.IsFalse(new Vec2I(2,3) == new Vec2I(3,10));
            Assert.IsFalse(new Vec2I(2,3) >= new Vec2I(3,10));
            Assert.IsFalse(new Vec2I(2,3) > new Vec2I(3,10));
            
            Assert.IsFalse(new Vec2I(2,3) < new Vec2I(1,0));
            Assert.IsFalse(new Vec2I(2,3) <= new Vec2I(1,0));
            Assert.IsTrue(new Vec2I(2,3) != new Vec2I(1,0));
            Assert.IsFalse(new Vec2I(2,3) == new Vec2I(1,0));
            Assert.IsTrue(new Vec2I(2,3) >= new Vec2I(1,0));
            Assert.IsTrue(new Vec2I(2,3) > new Vec2I(1,0));

            Assert.IsFalse(new Vec2I(3,4) < new Vec2I(3,4));
            Assert.IsTrue(new Vec2I(3,4) <= new Vec2I(3,4));
            Assert.IsFalse(new Vec2I(3,4) != new Vec2I(3,4));
            Assert.IsTrue(new Vec2I(3,4) == new Vec2I(3,4));
            Assert.IsTrue(new Vec2I(3,4) >= new Vec2I(3,4));
            Assert.IsFalse(new Vec2I(3,4) > new Vec2I(3,4));

            Assert.IsFalse(new Vec2I(1,2) < new Vec2I(0,2));
            Assert.IsFalse(new Vec2I(1,2) <= new Vec2I(0,2));
            Assert.IsTrue(new Vec2I(1,2) != new Vec2I(0,2));
            Assert.IsFalse(new Vec2I(1,2) == new Vec2I(0,2));
            Assert.IsTrue(new Vec2I(1,2) >= new Vec2I(0,2));
            Assert.IsFalse(new Vec2I(1,2) > new Vec2I(0,2));

            Assert.IsFalse(new Vec2I(1,2) < new Vec2I(0,3));
            Assert.IsFalse(new Vec2I(1,2) <= new Vec2I(0,3));
            Assert.IsTrue(new Vec2I(1,2) != new Vec2I(0,3));
            Assert.IsFalse(new Vec2I(1,2) == new Vec2I(0,3));
            Assert.IsFalse(new Vec2I(1,2) >= new Vec2I(0,3));
            Assert.IsFalse(new Vec2I(1,2) > new Vec2I(0,3));
            
        }

        [Test]
        public void MinMax()
        {
            Vec2I v = new Vec2I(1,2);
            Assert.IsTrue(v.MinDim == 0);
            Assert.IsTrue(v.MaxDim == 1);
            Assert.IsTrue(v.Minimum == 1);
            Assert.IsTrue(v.Maximum == 2);
            Assert.IsTrue(Vec2I.Min(new Vec2I(1,2), new Vec2I(3,2)) == new Vec2I(1,2));
            Assert.IsTrue(Vec2I.Max(new Vec2I(1,2), new Vec2I(3,2)) == new Vec2I(3,2));
        }

        [Test]
        public void ToStringTest()
        {
            Vec2I v = new Vec2I(7,17);
            Assert.AreEqual("Vec2I(7, 17)", v.ToString());
        }
    }

}
